package org.spring.bean.factory.support;

import com.sun.istack.internal.Nullable;
import lombok.Getter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spring.bean.exceptions.BeansException;
import org.spring.bean.factory.BeanFactory;
import org.spring.bean.factory.HierarchicalBeanFactory;
import org.spring.bean.factory.config.*;
import org.tool.core.lang.Assert;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * {@link BeanFactory} 实现的抽象基类，提供 {@link ConfigurableBeanFactory} SPI 的全部功能。
 * <i>not<i> 是否假设一个可列出的 bean 工厂：因此也可以用作 bean 工厂实现的基类，
 * 这些实现从一些后端资源获取 bean 定义（其中 bean 定义访问是一项昂贵的操作）。
 *
 * <p>此类提供单例缓存（通过其基类 {@link DefaultSingletonBeanRegistry}、单例原型确定、{@link FactoryBean} 处理、
 * 别名、bean 定义合并用于子 bean 定义和 bean 销毁（{@link DisposableBean} 接口，自定义销毁方法）。
 * 此外，它可以管理 bean 工厂层次结构（在未知 bean 的情况下委托给父级） ，通过实现 {@link HierarchicalBeanFactory} 接口。
 *
 * <p>子类要实现的主要模板方法是 {@link getBeanDefinition} 和 {@link createBean}，
 * 分别为给定的 bean 名称检索 bean 定义和为给定的 bean 定义创建 bean 实例。
 * 这些操作的默认实现可以在 {@link DefaultListableBeanFactory} 和 {@link AbstractAutowireCapableBeanFactory} 中找到。
 *
 * @author 李坤
 * @date 2022/4/20 16:34
 */
public abstract class AbstractBeanFactory extends DefaultSingletonBeanRegistry implements ConfigurableBeanFactory {

    private final Logger logger = LoggerFactory.getLogger(AbstractBeanFactory.class);
    /**
     * BeanPostProcessor 对象集合
     */
    @Getter
    private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
    /**
     * 从 bean 名称映射到合并的 RootBeanDefinition。
     */
    private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);
    /**
     * 指示是否注册了任何DestructionAwareBeanPostProcessors。
     */
    private volatile boolean hasDestructionAwareBeanPostProcessors;
    /**
     * 指示是否已注册任何InstantiationAwareBeanPostProcessors。
     */
    private volatile boolean hasInstantiationAwareBeanPostProcessors;

    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, null, args);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return (T) doGetBean(name, requiredType, null);
    }

    /**
     * 返回指定 bean 的一个实例，该实例可以是共享的，也可以是独立的。
     *
     * @param name         要检索的 bean 的名称
     * @param requiredType 要检索的 bean 的所需类型
     * @param args         使用显式参数创建 bean 实例时使用的参数（仅在创建新实例而不是检索现有实例时应用）
     *
     * @return bean 的一个实例
     *
     * @throws BeansException 如果无法创建 bean
     */
    protected Object doGetBean(String name, Class<?> requiredType, Object[] args) throws BeansException {
        logger.debug("开始查找名称为 {} 的 bean 对象", name);

        Assert.notNull(name, "Bean name must not be null");

        Object beanObject;

        if (Objects.isNull(beanObject = this.getSingleton(name))) {
            logger.debug("不存在名称为 {} 的 bean 对象，开始创建该对象", name);

            // 获取给定名称的 BeanDefinition 对象
            final BeanDefinition beanDefinition = getBeanDefinition(name);
            // 获取 RootBeanDefinition 对象
            final RootBeanDefinition rootBeanDefinition = getMergedBeanDefinition(name, beanDefinition);

            beanObject = createBean(name, rootBeanDefinition, args);
        }
        return beanObject;
    }

    /**
     * 如果给定 bean 的定义是子 bean 定义，则通过与父级合并返回给定顶级 bean 的 RootBeanDefinition。
     *
     * @param beanName       bean 定义的名称
     * @param beanDefinition 原始 bean 定义 (RootChildBeanDefinition)
     *
     * @return 给定 bean 的（可能合并的）RootBeanDefinition
     */
    private RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        RootBeanDefinition rootBeanDefinition;
        if (beanDefinition instanceof RootBeanDefinition) {
            rootBeanDefinition = (RootBeanDefinition) beanDefinition;
        } else {
            rootBeanDefinition = new RootBeanDefinition();
            rootBeanDefinition.setBeanClass(beanDefinition.getBeanClass());
            rootBeanDefinition.setBeanClassName(beanDefinition.getBeanClassName());
        }
        return rootBeanDefinition;
    }

    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");

        this.beanPostProcessors.remove(beanPostProcessor);
        // 跟踪它是否知道实例化销毁
        if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
            this.hasInstantiationAwareBeanPostProcessors = true;
        }
        if (beanPostProcessor instanceof DestructionAwareBeanPostProcessor) {
            this.hasDestructionAwareBeanPostProcessors = true;
        }
        // 添加到列表的末尾
        this.beanPostProcessors.add(beanPostProcessor);
    }

    @Override
    public int getBeanPostProcessorCount() {
        return beanPostProcessors.size();
    }

    @Override
    public boolean containsLocalBean(String name) {
        return Objects.nonNull(getSingleton(name)) || Objects.nonNull(getBeanDefinition(name));
    }

    /**
     * 获取给定名称的 bean 定义。
     *
     * @param beanName bean 名称
     *
     * @return bean 定义
     *
     * @throws BeansException 如果 bean 定义不存在
     */
    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;

    /**
     * 为给定的合并 bean 定义（和参数）创建一个 bean 实例。
     * 如果是子定义，bean 定义将已经与父定义合并。
     * <p>
     * 所有 bean 检索方法都委托给此方法以进行实际的 bean 创建。
     *
     * @param beanName       bean 的名字
     * @param beanDefinition bean 的合并 bean 定义
     * @param args           用于构造函数或工厂方法调用的显式参数
     *
     * @return bean 的新实例
     */
    protected abstract Object createBean(String beanName, RootBeanDefinition beanDefinition, @Nullable Object[] args);

}
